﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Nsf.Samples.RetryActivitySample.Infrastructure.ServiceBase
{
    public static class ExceptionToFaultConverter
    {
        private static readonly ReaderWriterLockSlim _convertersSync;
        private static readonly Dictionary<Type, Delegate> _converters;

        static ExceptionToFaultConverter()
        {
            _converters = new Dictionary<Type, Delegate>();
            _convertersSync = new ReaderWriterLockSlim();
        }

        private static Boolean TryGetConverterInternal(Type exceptionType, out Delegate converter)
        {
            _convertersSync.EnterReadLock();
            try
            {
                return _converters.TryGetValue(exceptionType, out converter);
            }
            finally
            {
                _convertersSync.ExitReadLock();
            }
        }

        public static void RegisterConverter<TException, TFault>(Func<TException, TFault> converter) where TException : Exception
        {
            _convertersSync.EnterWriteLock();
            try
            {
                _converters[typeof(TException)] = converter;
            }
            finally
            {
                _convertersSync.ExitWriteLock();
            }
        }

        public static Object ConvertException(Exception ex)
        {
            Delegate converter = null;
            var exceptionType = ex.GetType();
            while (exceptionType.BaseType != null && !TryGetConverterInternal(exceptionType, out converter))
            {
                if (converter == null)
                    exceptionType = exceptionType.BaseType;
            }
            if (converter == null)
                return null;
            return converter.DynamicInvoke(ex);
        }
    }
}
